//该源码对应的硬件，spi和iic复用了引脚，所以使用iic前要将spi结束（SPIR.end()），不过使用spi前好像不用结束iic



#include <_Time.h>//在我的电脑上Time.h库和HTTP client库有冲突，所以我将Time.h改成了_Time.h(需要在arduino的library文件夹里重命名Time.h和它对应的cpp文件）否则编译应该会出错
#include <WiFi.h>
#include <U8g2_for_Adafruit_GFX.h>  //甘草修改的u8g2图像库
#include <GxEPD2_BW.h>
#include <Adafruit_GFX.h>  //图像库

#include <string>
#include "gb2312.c"  //字体文件
#include <esp_sleep.h>
U8G2_FOR_ADAFRUIT_GFX u8g2Fonts;

#include <EEPROM.h>//文件管理相关
#include "FS.h"
#include "FFat.h"

#include "RTClib.h"//外设相关
PCF8563 RTC;
#include <AHT20.h>
AHT20 aht20;
;
#include <NTPClient.h>
#include "pictures.h"//图标文件
const byte lightpin = 10;


///////按键定义
#define button1 18
#define button2 9
#define button3 19
#define bt1click LOW//按下低电平
#define bt2click LOW
#define bt3click LOW

#define xshifting 0//x y显示的偏移量
#define yshifting 0

int theme = 1;//深色/浅色模式
#define FormC (theme == 1) ? GxEPD_BLACK : GxEPD_WHITE
#define BackC (theme == 1) ? GxEPD_WHITE : GxEPD_BLACK

int clocklocation=1;//自定义时钟在屏幕上的位置（0上1中2下）


extern void SettingStart();
extern void getTwifi();//联网获取时间
extern void getT(int &, int &, int &);//获取本地时间
extern void roundclockloop();//指针表盘时钟
extern void drawScale(String, int, int, int, int, float, float, bool);//可缩放绘制的图标绘制
extern bool tapcheck(int);//按键检测
extern void setAlarm(int, int);//设置时钟
File picfile;//“熄屏显示”的图片文件
extern String picout;//“熄屏显示”的图片文件读取后以String保存
int tick = 0;//局部刷新计次
struct Alarmt {//闹钟相关结构体
  bool ok;//是否启用闹钟
  int aHour;
  int aMin;
};
int defaultclock = 1;//默认转腕亮屏显示的时钟
Alarmt alTime = { false, 0, 0 };
#define FORMAT_SPIFFS_IF_FAILED true
//我自己的屏幕的引脚，因人而异改
GxEPD2_BW<GxEPD2_154, GxEPD2_154::HEIGHT> display(GxEPD2_154(/*CS=D8*/ 6, /*DC=D3*/ 1, /*RST=D4*/ 2, /*BUSY=D2*/ 3));  // 2.9黑白   GDEH029A1   128x296, SSD1608 (IL3820)
//GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> display(GxEPD2_154_D67(/*CS=D8*/ 6, /*DC=D3*/ 1, /*RST=D4*/ 2, /*BUSY=D2*/ 3));

//////////////////////////////////////////////////////以下是错误复位信息的获取和存储功能函数//////////////
#ifdef ESP_IDF_VERSION_MAJOR  // IDF 4+
#if CONFIG_IDF_TARGET_ESP32   // ESP32/PICO-D4
#include "esp32/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32C3
#include "esp32c3/rom/rtc.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/rtc.h"
#else
#error Target CONFIG_IDF_TARGET is not supported
#endif
#else  // ESP32 Before IDF 4.0
#include "rom/rtc.h"
#endif
void writeFile(fs::FS &fs, const char *path, const char *message) {
  Serial.printf("Writing file: %s\r\n", path);

  File file = fs.open(path, FILE_WRITE);
  if (!file) {
    Serial.println("- failed to open file for writing");
    return;
  }
  if (file.print(message)) {
    Serial.println("- file written");
  } else {
    Serial.println("- write failed");
  }
  file.close();
}
String verbose_print_reset_reason(int reason) {
  switch (reason) {
    case 1: return "Vbat power on reset";
    case 3: return "Software reset digital core";
    case 4: return "Legacy watch dog reset digital core";
    case 5: return "Deep Sleep reset digital core";
    case 6: return "Reset by SLC module, reset digital core";
    case 7: return "Timer Group0 Watch dog reset digital core";
    case 8: return "Timer Group1 Watch dog reset digital core";
    case 9: return "RTC Watch dog Reset digital core";
    case 10: return "Instrusion tested to reset CPU";
    case 11: return "Time Group reset CPU";
    case 12: return "Software reset CPU";
    case 13: return "RTC Watch dog Reset CPU";
    case 14: return "for APP CPU, reseted by PRO CPU";
    case 15: return "Reset when the vdd voltage is not stable";
    case 16: return "RTC Watch dog reset digital core and rtc module";
    default: return "NO_MEAN";
  }
}
String print_reset_reason(int reason) {
  switch (reason) {
    case 1: return "POWERON_RESET";           /**<1,  Vbat power on reset*/
    case 3: return "SW_RESET";                /**<3,  Software reset digital core*/
    case 4: return "OWDT_RESET";              /**<4,  Legacy watch dog reset digital core*/
    case 5: return "DEEPSLEEP_RESET";         /**<5,  Deep Sleep reset digital core*/
    case 6: return "SDIO_RESET";              /**<6,  Reset by SLC module, reset digital core*/
    case 7: return "TG0WDT_SYS_RESET";        /**<7,  Timer Group0 Watch dog reset digital core*/
    case 8: return "TG1WDT_SYS_RESET";        /**<8,  Timer Group1 Watch dog reset digital core*/
    case 9: return "RTCWDT_SYS_RESET";        /**<9,  RTC Watch dog Reset digital core*/
    case 10: return "INTRUSION_RESET";        /**<10, Instrusion tested to reset CPU*/
    case 11: return "TGWDT_CPU_RESET";        /**<11, Time Group reset CPU*/
    case 12: return "SW_CPU_RESET";           /**<12, Software reset CPU*/
    case 13: return "RTCWDT_CPU_RESET";       /**<13, RTC Watch dog Reset CPU*/
    case 14: return "EXT_CPU_RESET";          /**<14, for APP CPU, reseted by PRO CPU*/
    case 15: return "RTCWDT_BROWN_OUT_RESET"; /**<15, Reset when the vdd voltage is not stable*/
    case 16: return "RTCWDT_RTC_RESET";       /**<16, RTC Watch dog reset digital core and rtc module*/
    default: return "NO_MEAN";
  }
}

void writeResetreason() {
  String reason0 = print_reset_reason(rtc_get_reset_reason(0)) + "   " + verbose_print_reset_reason(rtc_get_reset_reason(0));
  writeFile(FFat, "/ResetReason.txt", reason0.c_str());
}
/////////////////////////////////////////////////////

extern void alarmget();
extern void mpu_init();//陀螺仪初始化
void setup() {

  Serial.begin(115200);
  pinMode(lightpin, OUTPUT);
  pinMode(18, INPUT);
  pinMode(19, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  digitalWrite(lightpin, HIGH);
  SPI.end();  // release standard SPI pins, e.g. SCK(18), MISO(19), MOSI(23), SS(5)
  ///////////
  Wire.begin(8, 7);
  mpu_init();
  if (aht20.begin() == false) {//温湿度传感器是否正常工作
    Serial.println("AHT20 not detected. Please check wiring. Freezing.");
    while (1) {
      digitalWrite(lightpin, LOW);
      delay(200);
      digitalWrite(lightpin, HIGH);
      delay(200);
    }
  }
  if (!RTC.isrunning()) {//rtc是否正常工作
    Serial.println("RTC is NOT running!");
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  // DateTime alarm0 = RTC.now();
  // alarm0.setminute(alarm0.minute()+int(1));
  //RTC.set_alarm(alarm0, { 1, 0, 0, 0 });
  // RTC.on_alarm();

  Wire.end();
  /////////////////////////////////////////////////////////////////////////////
  SPI.begin(7, 8, 8, 6);

  display.init(115200);
  u8g2Fonts.begin(display);  // 将u8g2过程连接到Adafruit GFX
  u8g2Fonts.setFontDirection(1);
  u8g2Fonts.setForegroundColor(FormC);  //GxEPD_BLACK            // 设置前景色
  u8g2Fonts.setBackgroundColor(BackC);  //GxEPD_WHITE      // 设置背景色
  u8g2Fonts.setFont(chinese_gb2312);
  display.fillScreen(FormC);
  display.setTextColor(BackC);
  display.display(0);
  display.setRotation(0);
  //display.firstPage();
  u8g2Fonts.setFontDirection(0);
  u8g2Fonts.setFont(chinese_gb2312);
  display.firstPage();
  //u8g2Fonts.drawUTF8(0, 0, "beginning...");

  Serial.println("beginning...");
  if (!FFat.begin()) {//文件系统初始化
    u8g2Fonts.drawUTF8(80, 100, "FFat Mount Failed,try to format...");
    display.nextPage();
    FFat.format();
    return;
  } else {
    Serial.println("ffat ok.");
    writeResetreason();
  }
  //picfile = FFat.open("/[p]pi
  EEPROM.begin(4096);  //只读存储器初始化c0.p", FILE_READ);
  //picout = picfile.readString();
  //Serial.println("picout");
  //Serial.println(picout);
  //Serial.println("picout");
  //picfile.close();
  // drawScale(picout, 0, 0, 200, 200, 1, 1, false);
  digitalWrite(lightpin, LOW);

  //从eeprom中获取设置信息，如果没有正常获取则主动初始化
  defaultclock = EEPROM.read(500);
  clocklocation=EEPROM.read(111);
  if (clocklocation != 0 && clocklocation != 1&&clocklocation !=2) clocklocation = 1;//
  if (defaultclock != 0 && defaultclock != 1&&defaultclock !=2) defaultclock = 0;
  int alarmchoice = EEPROM.read(6);
  if (alarmchoice != 0 && alarmchoice != 1 && alarmchoice != 2) {
    // pinMode(0, OUTPUT);
    // tone(0, 400);
    // delay(1000);
    // pinMode(0, INPUT);
    // return;
    alTime.ok=false;
  } else {
  alTime.aHour = EEPROM.read(2 * alarmchoice);
  alTime.aMin = EEPROM.read(2 * alarmchoice + 1);
  alTime.ok=true;
    SPI.end();
    Wire.begin(8,7);
    setAlarm(alTime.aMin, alTime.aHour);Wire.end();SPI.begin(7,8,8,6);
  }
 
    
  //
  //alarmget();
}
extern void homesetup();//主界面函数
//循环
extern DateTime nowtime;
void loop() {
  homesetup();
  //mousesetup();
}